From 4a18fe7ef27ab4fa86ce6133bd0131c184d5e9be Mon Sep 17 00:00:00 2001 From: Andrea Cimitan Date: Thu, 12 Jan 2012 13:29:52 -0500 Subject: [PATCH] Introduce gtk_window_get/set_attached_to() gtk_window_get/set_attached_to() is a new API that allows for windows to be attached to a GtkWidget. The attachment is a logical binding between the toplevel window and the widget that generated it; this kind of information is currently used to propagate style information from the widget to the window, but is also useful e.g. for accessibility. https://bugzilla.gnome.org/show_bug.cgi?id=666103 --- docs/reference/gtk/gtk3-sections.txt | 2 + gtk/gtk.symbols | 2 + gtk/gtkmenu.c | 8 ++- gtk/gtkwidget.c | 32 ++++++++- gtk/gtkwidgetprivate.h | 5 ++ gtk/gtkwindow.c | 104 +++++++++++++++++++++++++++ gtk/gtkwindow.h | 3 + 7 files changed, 152 insertions(+), 4 deletions(-) diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index f614e684e4..3b2317e136 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -5294,6 +5294,7 @@ gtk_window_set_gravity gtk_window_get_gravity gtk_window_set_position gtk_window_set_transient_for +gtk_window_set_attached_to gtk_window_set_destroy_with_parent gtk_window_set_hide_titlebar_when_maximized gtk_window_set_screen @@ -5352,6 +5353,7 @@ gtk_window_get_role gtk_window_get_size gtk_window_get_title gtk_window_get_transient_for +gtk_window_get_attached_to gtk_window_get_type_hint gtk_window_get_skip_taskbar_hint gtk_window_get_skip_pager_hint diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 59df40ce7a..5fbeeb87ae 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -3820,6 +3820,7 @@ gtk_window_get_skip_pager_hint gtk_window_get_skip_taskbar_hint gtk_window_get_title gtk_window_get_transient_for +gtk_window_get_attached_to gtk_window_get_type gtk_window_get_type_hint gtk_window_get_urgency_hint @@ -3891,6 +3892,7 @@ gtk_window_set_skip_taskbar_hint gtk_window_set_startup_id gtk_window_set_title gtk_window_set_transient_for +gtk_window_set_attached_to gtk_window_set_type_hint gtk_window_set_urgency_hint gtk_window_set_wmclass diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 40a841d5b5..03ad97030c 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -1202,9 +1202,8 @@ gtk_menu_attach_to_widget (GtkMenu *menu, if (gtk_widget_get_state_flags (GTK_WIDGET (menu)) != 0) gtk_widget_set_state_flags (GTK_WIDGET (menu), 0, TRUE); - /* we don't need to set the style here, since - * we are a toplevel widget. - */ + /* Attach the widget to the toplevel window. */ + gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), attach_widget); /* Fallback title for menu comes from attach widget */ gtk_menu_update_title (menu); @@ -1258,6 +1257,9 @@ gtk_menu_detach (GtkMenu *menu) } g_object_set_data (G_OBJECT (menu), I_(attach_data_key), NULL); + /* Detach the toplevel window. */ + gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), NULL); + g_signal_handlers_disconnect_by_func (data->attach_widget, (gpointer) attach_widget_screen_changed, menu); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 4d7b3bab09..0e4d1985ea 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -372,6 +372,11 @@ struct _GtkWidgetPrivate */ gchar *name; + /* The list of attached windows to this widget. + * We keep a list in order to call reset_style to all of them, + * recursively. */ + GList *attached_windows; + /* The style for the widget. The style contains the * colors the widget should be drawn in for each state * along with graphics contexts used to draw with and @@ -8314,6 +8319,9 @@ gtk_widget_reset_style (GtkWidget *widget) g_return_if_fail (GTK_IS_WIDGET (widget)); reset_style_recurse (widget, NULL); + + g_list_foreach (widget->priv->attached_windows, + (GFunc) reset_style_recurse, NULL); } #ifdef G_ENABLE_DEBUG @@ -13712,6 +13720,20 @@ _gtk_widget_get_sizegroups (GtkWidget *widget) return NULL; } +void +_gtk_widget_add_attached_window (GtkWidget *widget, + GtkWindow *window) +{ + widget->priv->attached_windows = g_list_prepend (widget->priv->attached_windows, window); +} + +void +_gtk_widget_remove_attached_window (GtkWidget *widget, + GtkWindow *window) +{ + widget->priv->attached_windows = g_list_remove (widget->priv->attached_windows, window); +} + /** * gtk_widget_path_append_for_widget: * @path: a widget path @@ -13800,7 +13822,15 @@ gtk_widget_get_path (GtkWidget *widget) * where style properties might be retrieved on that * situation. */ - widget->priv->path = gtk_widget_path_new (); + GtkWidget *attach_widget = NULL; + + if (GTK_IS_WINDOW (widget)) + attach_widget = gtk_window_get_attached_to (GTK_WINDOW (widget)); + + if (attach_widget != NULL) + widget->priv->path = gtk_widget_path_copy (gtk_widget_get_path (attach_widget)); + else + widget->priv->path = gtk_widget_path_new (); gtk_widget_path_append_for_widget (widget->priv->path, widget); } diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 35f99b9c9e..241a570bf8 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -100,6 +100,11 @@ void _gtk_widget_remove_sizegroup (GtkWidget *widget, gpointer group); GSList *_gtk_widget_get_sizegroups (GtkWidget *widget); +void _gtk_widget_add_attached_window (GtkWidget *widget, + GtkWindow *window); +void _gtk_widget_remove_attached_window (GtkWidget *widget, + GtkWindow *window); + void _gtk_widget_override_size_request (GtkWidget *widget, int width, int height, diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index a04d7fef60..452d3e1630 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -105,6 +105,7 @@ struct _GtkWindowPrivate { GtkMnemonicHash *mnemonic_hash; + GtkWidget *attach_widget; GtkWidget *default_widget; GtkWidget *focus_widget; GtkWindow *transient_parent; @@ -223,6 +224,7 @@ enum { PROP_DELETABLE, PROP_GRAVITY, PROP_TRANSIENT_FOR, + PROP_ATTACHED_TO, PROP_OPACITY, PROP_HAS_RESIZE_GRIP, PROP_RESIZE_GRIP_VISIBLE, @@ -967,6 +969,21 @@ gtk_window_class_init (GtkWindowClass *klass) GTK_TYPE_WINDOW, GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT)); + /** + * GtkWindow:attached-to: + * + * the widget attached to the window. + * + * Since: 3.4 + */ + g_object_class_install_property (gobject_class, + PROP_ATTACHED_TO, + g_param_spec_object ("attached-to", + P_("Attached to Widget"), + P_("The widget where the window is attached"), + GTK_TYPE_WIDGET, + GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT)); + /** * GtkWindow:opacity: * @@ -1277,6 +1294,9 @@ gtk_window_set_property (GObject *object, case PROP_TRANSIENT_FOR: gtk_window_set_transient_for (window, g_value_get_object (value)); break; + case PROP_ATTACHED_TO: + gtk_window_set_attached_to (window, g_value_get_object (value)); + break; case PROP_OPACITY: gtk_window_set_opacity (window, g_value_get_double (value)); break; @@ -1398,6 +1418,9 @@ gtk_window_get_property (GObject *object, case PROP_TRANSIENT_FOR: g_value_set_object (value, gtk_window_get_transient_for (window)); break; + case PROP_ATTACHED_TO: + g_value_set_object (value, gtk_window_get_attached_to (window)); + break; case PROP_OPACITY: g_value_set_double (value, gtk_window_get_opacity (window)); break; @@ -2375,6 +2398,20 @@ gtk_window_list_toplevels (void) return list; } +static void +remove_attach_widget (GtkWindow *window) +{ + GtkWindowPrivate *priv = window->priv; + + if (priv->attach_widget) + { + _gtk_widget_remove_attached_window (priv->attach_widget, window); + + g_object_unref (priv->attach_widget); + priv->attach_widget = NULL; + } +} + static void gtk_window_dispose (GObject *object) { @@ -2383,6 +2420,8 @@ gtk_window_dispose (GObject *object) gtk_window_set_focus (window, NULL); gtk_window_set_default (window, NULL); + remove_attach_widget (GTK_WINDOW (object)); + G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object); } @@ -2573,6 +2612,69 @@ gtk_window_get_transient_for (GtkWindow *window) return window->priv->transient_parent; } +/** + * gtk_window_set_attached_to: + * @window: a #GtkWindow + * @attach_widget (allow-none): a #GtkWidget, or %NULL + * + * Attach the window to a widget. Indicates that @window belongs to @widget. + * For example the window of a GtkMenu could belong to a GtkMenuBar or + * a GtkEntry or a GtkComboBox, and so on... + * + * GTK will use this information for styling the @window, + * for presenting it as a child of @widget in the accessibility tree + * and other things. + * + * Passing %NULL for @attach_widget detaches the window. + * + * Since: 3.4 + **/ +void +gtk_window_set_attached_to (GtkWindow *window, + GtkWidget *attach_widget) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (GTK_WIDGET (window) != attach_widget); + + priv = window->priv; + + remove_attach_widget (window); + + priv->attach_widget = attach_widget; + + if (priv->attach_widget) + { + _gtk_widget_add_attached_window (priv->attach_widget, window); + + g_object_ref_sink (priv->attach_widget); + } + + /* Update the style, as the widget path might change. */ + gtk_widget_reset_style (GTK_WIDGET (window)); +} + +/** + * gtk_window_get_attached_to: + * @window: a #GtkWindow + * + * Fetches the attach widget for this window. See + * gtk_window_set_attached_to(). + * + * Return value: (transfer none): the widget where the window is attached, + * or %NULL if the window is not attached to any widget. + * + * Since: 3.4 + **/ +GtkWidget * +gtk_window_get_attached_to (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + + return window->priv->attach_widget; +} + /** * gtk_window_set_opacity: * @window: a #GtkWindow @@ -4603,6 +4705,8 @@ gtk_window_destroy (GtkWidget *widget) if (priv->transient_parent) gtk_window_set_transient_for (window, NULL); + remove_attach_widget (GTK_WINDOW (widget)); + /* frees the icons */ gtk_window_set_icon_list (window, NULL); diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 17203070e2..3fcc5b2212 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -135,6 +135,9 @@ gboolean gtk_window_activate_default (GtkWindow *window); void gtk_window_set_transient_for (GtkWindow *window, GtkWindow *parent); GtkWindow *gtk_window_get_transient_for (GtkWindow *window); +void gtk_window_set_attached_to (GtkWindow *window, + GtkWidget *attach_widget); +GtkWidget *gtk_window_get_attached_to (GtkWindow *window); void gtk_window_set_opacity (GtkWindow *window, gdouble opacity); gdouble gtk_window_get_opacity (GtkWindow *window); -- 2.30.2